package com.ly.mp.busicen.rule.flow.action.plugin;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.StringUtils;

import com.ly.mp.busicen.rule.flow.IDataVolume;
import com.ly.mp.busicen.rule.flow.action.ActionException;
import com.ly.mp.busicen.rule.flow.action.ActionExecuteBase;
import com.ly.mp.busicen.rule.flow.action.ActionResult;
import com.ly.mp.busicen.rule.flow.action.IAction;
import com.ly.mp.busicen.rule.flow.action.IActionResult;
import com.ly.mp.busicen.rule.flow.action.IActionResult.Signal;

public class ActionExecuteScript extends ActionExecuteBase implements ApplicationContextAware{
	
	static final Logger log = LoggerFactory.getLogger(ActionExecuteScript.class);
	
	static final Logger scriptlog = LoggerFactory.getLogger("com.ly.mp.busicen.rule.action.SCRIPT");
	
	public static ScriptEngine engine;	
	
	public ApplicationContext appcontext;
	
	public static Map<String,Object> extention = new HashMap<>();
	
	ConcurrentHashMap<Integer, CompiledScript> sctripts = new ConcurrentHashMap<Integer, CompiledScript>();
	
	static {
		ScriptEngineManager manager = new ScriptEngineManager();
        engine = manager.getEngineByName("nashorn");
        engine.getContext().getWriter();
        extention.put("log", scriptlog);
	}

	@Override
	public IActionResult execute(IAction action, IDataVolume dataVolume) {
		ActionResult result = ActionResult.create();
		result.action(action.action());
		try {
			CompiledScript compiledScript = getCompiledScript(action.content());
			Bindings bindings = createBindings(action, dataVolume);
			Object jsResp = compiledScript.eval(bindings);
			result.data(jsResp);
			dataVolume.ext().put(action.action(), jsResp);
			if (!StringUtils.isEmpty(jsResp)&&jsResp instanceof String) {
				String strResp = String.valueOf(jsResp);
				String[] respArray = strResp.split(":");
				if (respArray.length>=2) {
					String flag = respArray[0];
					String nextActionLable = respArray[1];
					if ("S".equals(flag)) {
						result.signal(Signal.CONTINUE);
						result.msg(action.msg());
						result.nextAction(defaultNextActionCode(action, nextActionLable));
						log.info("规则引擎动态脚本{}校验结果为继续，下一动作节点为{}",action.action(),result.nextAction());
					}else {						
						log.info("规则引擎动态脚本执行结果中断");
						result.signal(Signal.BREAK);
						//特殊处理
						if (StringUtils.isEmpty(nextActionLable)) {
							result.msg(action.msg());
						}else {
							result.msg(nextActionLable);
							result.setConvertMsg(false);
						}
					}
				}else if (strResp.startsWith("F:")) {
					log.info("规则引擎动态脚本执行结果中断（F:）");
					result.signal(Signal.BREAK);
					result.msg(action.msg());
				}else {
					log.info("规则引擎动态脚本执行结果正常");
					result.signal(Signal.CONTINUE);
					result.msg(action.msg());
					result.nextAction(defaultNextActionCode(action, null));
				}
				
			}else {
				log.info("规则引擎动态脚本执行结果正常");
				result.signal(Signal.CONTINUE);
				result.msg(action.msg());
				result.nextAction(defaultNextActionCode(action, null));
			}
		} catch (Exception e) {
			result.signal(Signal.EXCPT);
			result.excpt(e);
		}		
		return result;
	}
	
	
	Bindings createBindings(IAction action, IDataVolume dataVolume) {
		Bindings bindings = engine.createBindings();
		bindings.put("data", dataVolume);
		bindings.put("action", action);
		bindings.put("app", appcontext);
		
		
		bindings.put("extention", extention);
		return bindings;
	}
	
	public CompiledScript getCompiledScript(String script) {
		if (StringUtils.isEmpty(script)) {
			throw new ActionException("Script is empty");
		}
		int hashcode = script.hashCode();
		CompiledScript compiledScript = sctripts.get(hashcode);
		if (compiledScript==null) {
			Compilable compilable = (Compilable) engine;
			try {
				compiledScript = compilable.compile(script);				
			} catch (ScriptException e) {
				log.error("规则引擎动态脚本编译异常",e);
				throw new ActionException("Java Script compile error");
			}
			sctripts.put(hashcode, compiledScript);
		}
		return compiledScript;
	}
	

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		appcontext = applicationContext;		
	}

	
	public static void main(String[] args) {
		String ss = "F:null:null";
		String[] strs = ss.split(":");
		System.out.println(strs.length);
	}
}
